// 
//
//	File: MaterialProperties.h
//

// Definition of the material properties.

#ifndef OY_MATERIALPROPERTIES_H
#define OY_MATERIALPROPERTIES_H

#include <cassert>
#include <d3d9.h>
#include "../../OyRenderer/OyEngine.h"



// forwards
class DX9VertexShader;
class DX9PixelShader;



class MaterialProperty
{
public :
	
	virtual ~MaterialProperty() {}
	virtual MaterialProperty * Clone() const { assert( false ); return 0; }

	// public interface
	virtual void Begin() const = 0;
	virtual void End() const {}
	virtual bool RegisterEnd() const { return false; }
	virtual void Update( float elapsedTime ) {}
	virtual void UpdateTexture(unsigned int texID, int unit) {}
	virtual bool IsDynamic() const { return false; }	
};


// defines
#define REGISTER_BEGIN			virtual void Begin() const;
#define REGISTER_END			virtual bool RegisterEnd() const { return true; } virtual void End() const;
#define REGISTER_UPDATE			virtual bool IsDynamic() const { return true; } virtual void Update( float elapsedTime );


// ColorProperty
class ColorProperty : public MaterialProperty
{
public :
	enum ColorOperation
	{
		CO_Replace,		// replace the current color
		CO_Add,			// add this color to the current color
		CO_Multiply		// multiply this color with the current color
	};
	inline ColorProperty( const D3DCOLOR & color, ColorOperation op = CO_Replace ) : color_( color ), op_( op ) {}
	inline void Apply( D3DCOLOR & dest ) const;


protected :
	D3DCOLOR color_;
	ColorOperation op_;
};


// AmbientColorProperty
class AmbientColorProperty : public ColorProperty
{
public :
	inline AmbientColorProperty( const D3DCOLOR & color, ColorOperation op = CO_Replace ) : ColorProperty( color, op ) {}
	virtual MaterialProperty * Clone() const { return new AmbientColorProperty( color_, op_ ); }
	REGISTER_BEGIN;

private :
	static D3DCOLOR current_;
};

/*
// DiffuseColorProperty
class DiffuseColorProperty : public ColorProperty
{
public :
	inline DiffuseColorProperty( const D3DCOLOR & color, ColorOperation op = CO_Replace ) : ColorProperty( color, op ) {}
	virtual MaterialProperty * Clone() const { return new DiffuseColorProperty( color_, op_ ); }
	REGISTER_BEGIN;

private :
	static D3DCOLOR current_;
};

// EmissiveColorProperty
class EmissiveColorProperty : public ColorProperty
{
public :
	inline EmissiveColorProperty( const D3DCOLOR & color, ColorOperation op = CO_Replace ) : ColorProperty( color, op ) {}
	virtual MaterialProperty * Clone() const { return new EmissiveColorProperty( color_, op_ ); }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	static D3DCOLOR current_;
};

// SpecularProperty
class SpecularColorProperty : public ColorProperty
{
public :
	inline SpecularColorProperty( const D3DCOLOR & color, ColorOperation op ) : ColorProperty( color, op ) {}
	virtual MaterialProperty * Clone() const { return new SpecularColorProperty( color_, op_ ); }
	REGISTER_BEGIN;

private :
	static D3DCOLOR current_;
};


// ShininessProperty
class ShininessProperty : public MaterialProperty
{
public :
	inline ShininessProperty( float value ) : value_( value ) {}
	virtual MaterialProperty * Clone() const { return new ShininessProperty( value_ ); }
	REGISTER_BEGIN;

private :
	float value_;
};
*/

// OyMaterialProperty
// If Light is disable, OyMaterialProperty will unusable
class OyMaterialProperty : public MaterialProperty
{
public:
	inline OyMaterialProperty( unsigned int matID ): material_ID(matID) {}
	virtual MaterialProperty * Clone() const { return new OyMaterialProperty( material_ID ); }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	unsigned int material_ID;
};


// TextureProperty
class TextureProperty : public MaterialProperty
{
public:
	inline TextureProperty( unsigned int texID, int unit ) : texture_ID( texID ), unit_( unit ) {}
	virtual MaterialProperty * Clone() const { return new TextureProperty( texture_ID, unit_ ); }
	inline void UpdateTexture(unsigned int texID, int unit) { texture_ID = texID; unit_ = unit; }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	unsigned int texture_ID;
	int unit_;
};


// DisableTextureProperty
class DisableTextureProperty : public MaterialProperty
{
public :
	inline DisableTextureProperty( int unit ) : unit_( unit ) {}
	virtual MaterialProperty * Clone() const { return new DisableTextureProperty( unit_ ); }
	REGISTER_BEGIN;
	//REGISTER_END;

private :
	int unit_;
};


// AlphaBlendOpProperty
class AlphaBlendOpProperty : public MaterialProperty
{
public :
	inline AlphaBlendOpProperty( D3DBLENDOP op ) : op_( op ) {}
	virtual MaterialProperty * Clone() const { return new AlphaBlendOpProperty( op_ ); }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	D3DBLENDOP op_;
};


// AlphaBlendProperty
class AlphaBlendProperty : public MaterialProperty
{
public :
	inline AlphaBlendProperty( D3DBLEND src, D3DBLEND dst ) : src_( src ), dst_( dst ) {}
	virtual MaterialProperty * Clone() const { return new AlphaBlendProperty( src_, dst_ ); }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	D3DBLEND src_;
	D3DBLEND dst_;
};

// AlphaBlendAlphaProperty
class AlphaBlendAlphaProperty : public MaterialProperty
{
public :
	inline AlphaBlendAlphaProperty( D3DBLEND src, D3DBLEND dst, D3DBLENDOP op ) : src_(src), dst_(dst), op_(op) {}
	virtual MaterialProperty * Clone() const { return new AlphaBlendAlphaProperty( src_, dst_, op_ ); }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	D3DBLEND src_;
	D3DBLEND dst_;
	D3DBLENDOP op_;
};


// AlphaTestFuncProperty
class AlphaTestFuncProperty : public MaterialProperty
{
public :
	inline AlphaTestFuncProperty( D3DCMPFUNC func ) : func_( func ) {}
	virtual MaterialProperty * Clone() const { return new AlphaTestFuncProperty( func_ ); }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	D3DCMPFUNC func_;
};

// AlphaTestRefProperty
class AlphaTestRefProperty : public MaterialProperty
{
public :
	inline AlphaTestRefProperty( DWORD ref ) : ref_( ref ) {}
	virtual MaterialProperty * Clone() const { return new AlphaTestRefProperty( ref_ ); }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	DWORD ref_;
};

class StencilProperty : public MaterialProperty
{
public :
	inline StencilProperty( D3DCMPFUNC func, D3DSTENCILOP fail,	D3DSTENCILOP zfail,
		D3DSTENCILOP pass, int ref,	DWORD mask,	DWORD writemask ) : func_(func),
		fail_(fail), zfail_(zfail), pass_(pass), ref_(ref), mask_(mask), writemask_(writemask){}
	virtual MaterialProperty * Clone() const { return new StencilProperty( func_, fail_, zfail_,
		pass_, ref_, mask_, writemask_ ); }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	D3DCMPFUNC func_;
	D3DSTENCILOP fail_;
	D3DSTENCILOP zfail_;
	D3DSTENCILOP pass_;
	int ref_;
	DWORD mask_;
	DWORD writemask_;
};

// TextureFactorProperty
class TextureFactorProperty : public MaterialProperty
{
public :
	inline TextureFactorProperty( DWORD value ) : value_( value ) {}
	virtual MaterialProperty *	Clone() const { return new TextureFactorProperty( value_ ); }
	inline DWORD				&GetValue() { return value_; }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	DWORD value_;
};


// DepthEnableProperty
class DepthEnableProperty : public MaterialProperty
{
public :
	inline DepthEnableProperty( D3DZBUFFERTYPE Ztype ) : ZBufferType( Ztype ) {}
	virtual MaterialProperty * Clone() const { return new DepthEnableProperty(ZBufferType); }
	REGISTER_BEGIN;
	REGISTER_END;
	
private :
	D3DZBUFFERTYPE ZBufferType;
};


// DepthBiasProperty
class DepthBiasProperty : public MaterialProperty
{
public :
	inline DepthBiasProperty( float bias ) : bias_( bias ) {}
	virtual MaterialProperty * Clone() const { return new DepthBiasProperty( bias_ ); }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	float bias_;
};



// DepthFuncProperty
class DepthFuncProperty : public MaterialProperty
{
public :
	inline DepthFuncProperty( D3DCMPFUNC func ) : func_( func ) {}
	virtual MaterialProperty * Clone() const { return new DepthFuncProperty( func_ ); }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	D3DCMPFUNC func_;
};


// ColorMaskProperty
class ColorMaskProperty : public MaterialProperty
{
public :
	inline ColorMaskProperty( UINT Mask ) : MaskValue( Mask ) {}
	virtual MaterialProperty * Clone() const { return new ColorMaskProperty(MaskValue); }
	REGISTER_BEGIN;
	REGISTER_END;
	
private:
	UINT MaskValue;
};


// CullingModeProperty
class CullingModeProperty : public MaterialProperty
{
public :
	inline CullingModeProperty( D3DCULL cull ) : cull_( cull ) {}
	virtual MaterialProperty * Clone() const { return new CullingModeProperty(cull_); }
	REGISTER_BEGIN;
	REGISTER_END;
	
private:
	D3DCULL cull_;
};


// ShaderProperty
class ShaderProperty : public MaterialProperty
{
public :
	inline ShaderProperty( DX9VertexShader *pVS = 0, DX9PixelShader *pPS = 0 ) : pVSShader( pVS ), pPSShader(pPS) {}
	~ShaderProperty();
	virtual MaterialProperty * Clone() const { return new ShaderProperty( pVSShader, pPSShader ); }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	DX9VertexShader *pVSShader;
	DX9PixelShader *pPSShader;
};


// EnableStateProperty
class EnableStateProperty : public MaterialProperty
{
public :
	inline EnableStateProperty( D3DRENDERSTATETYPE cap ) : cap_( cap ) {}
	virtual MaterialProperty * Clone() const { return new EnableStateProperty( cap_ ); }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	D3DRENDERSTATETYPE cap_;
};


// DisableStateProperty
class DisableStateProperty : public MaterialProperty
{
public :
	inline DisableStateProperty( D3DRENDERSTATETYPE cap ) : cap_( cap ) {}
	virtual MaterialProperty * Clone() const { return new DisableStateProperty( cap_ ); }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	D3DRENDERSTATETYPE cap_;
};


// LineDrawingProperty
class LineDrawingProperty : public MaterialProperty
{
public :
	virtual MaterialProperty * Clone() const { return new LineDrawingProperty(); }
	REGISTER_BEGIN;
	REGISTER_END;
};

// LightingDisableProperty
class LightingDisableProperty : public MaterialProperty
{
public :
	inline LightingDisableProperty( DWORD bLightDisable ) : lightingDisable_( bLightDisable ) {}
	virtual MaterialProperty * Clone() const { return new LightingDisableProperty( lightingDisable_ ); }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	DWORD lightingDisable_;
};

// SamplerStateProperty
class SamplerStateProperty : public MaterialProperty
{
public :
	inline SamplerStateProperty( DWORD Sampler,	D3DSAMPLERSTATETYPE Type, DWORD Value ) : Sampler_(Sampler), Type_(Type), Value_(Value) {}
	virtual MaterialProperty *	Clone() const { return new SamplerStateProperty( Sampler_, Type_, Value_ ); }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	DWORD Sampler_;
	D3DSAMPLERSTATETYPE Type_;
	DWORD Value_;
};

// TextureStageStateProperty
class TextureStageStateProperty : public MaterialProperty
{
public :
	inline TextureStageStateProperty( DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value ) : Stage_(Stage), Type_(Type), Value_(Value) {}
	virtual MaterialProperty * Clone() const { return new TextureStageStateProperty( Stage_, Type_, Value_ ); }
	REGISTER_BEGIN;
	REGISTER_END;

private :
	DWORD Stage_;
	D3DTEXTURESTAGESTATETYPE Type_;
	DWORD Value_;
};


#endif
